package com.share.device.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.share.device.domain.Cabinet;
import com.share.device.domain.Station;
import com.share.device.domain.StationLocation;
import com.share.device.service.ICabinetService;
import com.share.device.service.IDeviceService;
import com.share.device.service.IMapService;
import com.share.device.service.IStationService;
import com.share.device.vo.StationVo;
import com.share.rules.api.RemoteFeeRuleService;
import com.share.rules.api.domain.FeeRule;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.data.geo.Circle;
import org.springframework.data.geo.Distance;
import org.springframework.data.geo.Metrics;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.geo.GeoJsonPoint;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * @author zxl
 * @date 2025年03月21日 10:49
 */
@Slf4j
@Service
@SuppressWarnings({"unchecked", "rawtypes"})
public class DeviceServiceImpl implements IDeviceService {
    @Resource
    MongoTemplate mongoTemplate;

    @Resource
    IStationService stationService;

    @Resource
    ICabinetService cabinetService;

    @Resource
    RemoteFeeRuleService remoteFeeRuleService;

    @Resource
    IMapService mapService;

    // 声明Random对象为成员变量
    private final Random random = new Random();
    /**
     * 获取附近站点信息列表
     * @param latitude
     * @param longitude
     * @param radius
     * @return
     */
    @Override
    public List<StationVo> nearbyStation(String latitude, String longitude, Integer radius) {
        // 坐标，确定中心点
        // GeoJsonPoint(double x, double y) x 表示经度，y 表示纬度。
        GeoJsonPoint geoJsonPoint = new GeoJsonPoint(Double.parseDouble(longitude), Double.parseDouble(latitude));
        //画圈的半径,50km范围
        Distance distance = new Distance(radius, Metrics.KILOMETERS);
        //画了一个圆圈
        Circle circle = new Circle(geoJsonPoint, distance);
        //条件查询location在圆圈内的数据
        Query query = Query.query(Criteria.where("location").withinSphere(circle));
        List<StationLocation> stationLocationList = mongoTemplate.find(query, StationLocation.class);
        if (CollectionUtils.isEmpty(stationLocationList)) return Collections.emptyList();

        // 组装数据
        List<Long> stationIdList = stationLocationList.stream().map(StationLocation::getStationId).toList();
        //获取站点列表
        List<Station> stationList = stationService.list(new LambdaQueryWrapper<Station>().in(Station::getId, stationIdList).isNotNull(Station::getCabinetId));

        // 获取柜机id列表
        List<Long> cabinetIdList = stationList.stream().map(Station::getCabinetId).toList();

        // 获取柜机id与柜机信息Map
        Map<Long, Cabinet> cabinetIdToCabinetMap = cabinetService.listByIds(cabinetIdList).stream().collect(
                Collectors.toMap(Cabinet::getId, cabinet -> cabinet)
        );

        //获取费用规则列表
        List<Long> feeRuleIdList = stationList.stream().map(Station::getFeeRuleId).toList();
        // 获取费用规则id与费用规则信息Map
        Map<Long, FeeRule> feeRuleIdToFeeRuleMap = remoteFeeRuleService.getFeeRuleList(feeRuleIdList).getData().stream().collect(
                Collectors.toMap(FeeRule::getId, feeRule -> feeRule)
        );
        // 地图距离调用接口限制，只查前10个的距离，避免接口调用次数过多
        int limit = 3;
        AtomicInteger i = new AtomicInteger();
        List<StationVo> stationVoList = new ArrayList<>();
        stationList.forEach(item -> {
            StationVo stationVo = new StationVo();
            BeanUtils.copyProperties(item, stationVo);
            if (i.getAndIncrement() < limit){
                // 计算距离
                Double distanceItem = mapService.calculateDistance(longitude, latitude, item.getLongitude().toString(), item.getLatitude().toString());
                // 设置距离，单位米
                stationVo.setDistance(distanceItem);
            } else {
                // 超过10次，则设置距离为随机数
                stationVo.setDistance(createRandom());
            }

            // 获取柜机信息
            Cabinet cabinet = cabinetIdToCabinetMap.get(item.getCabinetId());
            // 可用充电宝数量大于0，设置isUsable为1 可借用，否则设置为0 不可借用
            stationVo.setIsUsable(cabinet.getAvailableNum() > 0 ? "1" : "0");
            // 空闲插槽数量大于0，可归还1，否则设置为0不可归还
            stationVo.setIsReturn(cabinet.getFreeSlots() > 0 ? "1" : "0");

            // 获取费用规则
            FeeRule feeRule = feeRuleIdToFeeRuleMap.get(item.getFeeRuleId());
            // 站点中的费用规则，实际是费用规则的描述
            stationVo.setFeeRule(feeRule.getDescription());

            stationVoList.add(stationVo);
        });
        return stationVoList;
    }

    /**
     * 根据id获取门店详情
     * @param id 门店站点id
     * @param longitude
     * @param latitude
     * @return
     */
    @Override
    public StationVo getStation(Long id, String longitude, String latitude) {
        // 根据id获取门店站点基本信息
        Station station = stationService.getById(id);
        StationVo stationVo = new StationVo();
        BeanUtils.copyProperties(station, stationVo);
        // 计算距离
        Double distance = mapService.calculateDistance(longitude, latitude, station.getLongitude().toString(), station.getLatitude().toString());
        stationVo.setDistance(distance);

        // 获取柜机信息
        Cabinet cabinet = cabinetService.getById(station.getCabinetId());
        // 站点是否可用,柜机可用充电宝数量大于0，站点可用1，否则设置为0 不可借用
        stationVo.setIsUsable(cabinet.getAvailableNum() > 0 ? "1" : "0");
        // 获取空闲插槽数量是否大于0，大于0设置为可归还1，否则设置为0不可归还
        stationVo.setIsReturn(cabinet.getFreeSlots() > 0 ? "1" : "0");

        // 获取费用规则
        FeeRule feeRule = remoteFeeRuleService.getFeeRule(station.getFeeRuleId()).getData();
        stationVo.setFeeRule(feeRule.getDescription());
        return stationVo;
    }

    public Double createRandom() {
        BigDecimal randomDouble = BigDecimal.valueOf(random.nextDouble(1000));

        // 保留两位小数，并进行四舍五入
        BigDecimal roundedValue = randomDouble.setScale(1, RoundingMode.HALF_UP);
        return roundedValue.doubleValue();
    }
}
